// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#ifndef OPENTITAN_SW_DEVICE_LIB_DIF_DIF_SRAM_CTRL_H_
#define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_SRAM_CTRL_H_

/**
 * @file
 * @brief <a href="/book/hw/ip/sram_ctrl/">SRAM Controller</a> Device Interface
 * Functions
 */

#include <stdint.h>

#include "sw/device/lib/base/multibits.h"

#include "sw/device/lib/dif/autogen/dif_sram_ctrl_autogen.h"

#ifdef __cplusplus
extern "C" {
#endif  // __cplusplus

/**
 * SRAM Controller status information bitfield.
 */
typedef uint32_t dif_sram_ctrl_status_bitfield_t;

/**
 * SRAM Controller status flags.
 *
 * Invariants are used to extract information encoded in
 * `dif_sram_ctrl_status_bitfield_t`.
 *
 * More than one status flag can be set at the same time, and a caller may use
 * these invariants to look-up individual or a group of flags.
 *
 * Note: these must match the autogenerated register definition bit offsets.
 */
typedef enum dif_sram_ctrl_status {
  /**
   * Bus integrity fault is detected. This error triggers a fatal_error alert.
   * This condition is terminal.
   */
  kDifSramCtrlStatusBusIntegErr = 0x1,
  /**
   * Initialization counter has reached an invalid state. This error triggers
   * a fatal_error alert. This condition is terminal.
   */
  kDifSramCtrlStatusInitErr = (0x1 << 1),
  /**
   * SRAM Controller has received an escalate request, the scrambling keys have
   * been reset to the default values and all subsequent memory requests will
   * be blocked. This condition is terminal.
   */
  kDifSramCtrlStatusEscalated = (0x1 << 2),
  /**
   * New scrambling key has been successfully obtained from OTP. If the flag is
   * not set, the SRAM contents are still scrambled, but a default all-zero key
   * and nonce are used to do so.
   */
  kDifSramCtrlStatusScrKeyValid = (0x1 << 3),
  /**
   * Scrambling key has been derived from a valid key seed in OTP. When
   * `kDifSramCtrlStatusScrKeyValid` is set, but this flag is unset - the
   * scrambling key is still ephemeral (i.e., it is derived using entropy from
   * CSRNG), but a default all-zero value is used as the key seed. This could
   * happen when the scrambling key seeds have not yet been provisioned to OTP.
   */
  kDifSramCtrlStatusScrKeySeedValid = (0x1 << 4),
  /**
   * Hardware initialization triggered via `dif_sram_ctrl_scramble` or
   * `dif_sram_ctrl_wipe` has completed.
   */
  kDifSramCtrlStatusInitDone = (0x1 << 5),
} dif_sram_ctrl_status_t;

/**
 * SRAM Controller lockable functionality.
 */
typedef enum dif_sram_ctrl_lock {
  /**
   * SRAM scrambling key renewal and "wiping" lock, which includes the following
   * API: `dif_sram_ctrl_scramble`, `dif_sram_ctrl_request_new_key`
   * and `dif_sram_ctrl_wipe`.
   */
  kDifSramCtrlLockCtrl = 0,
  /**
   * Code execution from SRAM lock, which includes the following API:
   * `dif_sram_ctrl_exec_set_enabled`.
   *
   * Note: this setting may not be available depending on the OTP configuration
   * of the chip (EN_SRAM_IFETCH fuse).
   */
  kDifSramCtrlLockExec,
  /**
   * Readback feature lock. When locked, disabling or enabling the SRAM readback
   * feature is not available anymore. Includes the following API:
   * `dif_sram_ctrl_readback_set`.
   */
  kDifSramCtrlLockReadback,
} dif_sram_ctrl_lock_t;

/**
 * Performs blocking SRAM scrambling operation.
 *
 * This function should only be called when the data is no longer used.
 *
 * This is a compound operation covering both data and address "scrambling".
 * In other words logical re-mapping of the physical addresses and data
 * scrambling, followed by the entire SRAM overwriting with a pseudo-random
 * data.
 *
 * The intention of this operation is to ensure that there is no predefined
 * values or predictable data that could potentially make "unscrambling"
 * easier.
 *
 * This operation is expected to take a significant amount of CPU cycles. If
 * a non-blocking alternative is required, then `dif_sram_ctrl_request_new_key`,
 * should be used followed by `dif_sram_ctrl_wipe`. The status of these
 * operations can be found through `dif_sram_ctrl_get_status`.
 *
 * Note: when dealing with the Main RAM, additional implication is that the
 *       C runtime can be invalidated by the call to this function, and must be
 *       re-configured prior to any C code execution.
 *
 * @param sram_ctrl A SRAM Controller handle.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_sram_ctrl_scramble(const dif_sram_ctrl_t *sram_ctrl);

/**
 * Requests a new scrambling key.
 *
 * This function should only be called when the data is no longer used.
 *
 * On successful completion SRAM addresses (due to different logical mapping of
 * the physical addresses) and the data are scrambled. However, it is
 * recommended to additionally overwrite SRAM with pseudo-random data by calling
 * `dif_sram_ctrl_wipe`. This should minimize the chances of revealing the XOR
 * key-stream.
 *
 * This operation is expected to take a significant amount of CPU cycles. The
 * status can be checked via `kDifSramCtrlStatusScrKeyValid`, which is useful
 * when a non-blocking work flow is desirable. Otherwise any SRAM access will
 * automatically block until this operation has finished.
 *
 * Note: when dealing with the Main RAM, additional implication is that the
 *       C runtime can be invalidated by the call to this function, and must be
 *       re-configured prior to any C code execution.
 *
 * Note: during an ongoing memory initialization, the hardware ignores the key
 *       request.
 *
 * @param sram_ctrl A SRAM Controller handle.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_sram_ctrl_request_new_key(const dif_sram_ctrl_t *sram_ctrl);

/**
 * Overwrites "wipes" the entire SRAM with pseudo-random data.
 *
 * This function should only be called when the data is no longer used.
 *
 * This operation is expected to take a significant amount of CPU cycles. The
 * status can be checked via `kDifSramCtrlStatusInitDone`, which is useful when
 * a non-blocking work flow is desirable. Otherwise any SRAM access will
 * automatically block until this operation has finished.
 *
 * Note: when dealing with the Main RAM, additional implication is that the
 *       C runtime can be invalidated by the call to this function, and must be
 *       re-configured prior to any C code execution.
 *
 * Note: during this memory initialization, the hardware ignores key requests
 *       that are issued while this operation is pending.
 *
 * @param sram_ctrl A SRAM Controller handle.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_sram_ctrl_wipe(const dif_sram_ctrl_t *sram_ctrl);

/**
 * Checks whether execution from SRAM is currently enabled or disabled.
 *
 * @param sram_ctrl A SRAM Controller handle.
 * @param[out] state Out-param toggle state of the SRAM execution.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_sram_ctrl_exec_get_enabled(const dif_sram_ctrl_t *sram_ctrl,
                                            dif_toggle_t *state);

/**
 * Sets whether execution from SRAM enabled or disabled.
 *
 * @param sram_ctrl A SRAM Controller handle.
 * @param state The new toggle state for the SRAM execution.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_sram_ctrl_exec_set_enabled(const dif_sram_ctrl_t *sram_ctrl,
                                            dif_toggle_t state);

/**
 * Sets whether the SRAM readback feature is enabled or disabled.
 *
 * @param sram_ctrl A SRAM Controller handle.
 * @param state The new toggle state for the SRAM readback feature.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_sram_ctrl_readback_set(const dif_sram_ctrl_t *sram_ctrl,
                                        dif_toggle_t state);

/**
 * Queries the SRAM Controller status.
 *
 * `dif_sram_ctrl_status_t` is used to then extract individual status bits.
 *
 * @param sram_ctrl A SRAM Controller handle.
 * @param[out] SRAM Controller status bitfield.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_sram_ctrl_get_status(const dif_sram_ctrl_t *sram_ctrl,
                                      dif_sram_ctrl_status_bitfield_t *status);

/**
 * Locks out requested SRAM Controller functionality.
 *
 * This function is reentrant: calling it while functionality is locked will
 * have no effect and return `kDifOk`.
 *
 * @param sram_ctrl A SRAM Controller handle.
 * @param lock SRAM functionality to lock.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_sram_ctrl_lock(const dif_sram_ctrl_t *sram_ctrl,
                                dif_sram_ctrl_lock_t lock);

/**
 * Checks whether requested SRAM Controller functionality is locked.
 *
 * @param sram_ctrl A SRAM Controller handle.
 * @param lock SRAM functionality to query locked state for.
 * @param[out] is_locked Out-param for the locked state.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_sram_ctrl_is_locked(const dif_sram_ctrl_t *sram_ctrl,
                                     dif_sram_ctrl_lock_t lock,
                                     bool *is_locked);

/**
 * Checks whether requested SRAM Controller successfully obtained a new key.
 *
 * success is set to kMultiBitBool4True if a key rotation was successful.
 *
 * The clear parameter can be set to kMultiBitBool4True in order to clear
 * the key rotation state back to kMultiBitBool4False after reading it.
 * If the state should not be cleared, set clear to kMultiBitBool4False.
 *
 * @param sram_ctrl A SRAM Controller handle.
 * @param[out] success Outparam for the success state.
 * @param clear Parameter indicating whether to CSR should be cleared after
 *              reading.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_sram_ctrl_scr_key_rotated(const dif_sram_ctrl_t *sram_ctrl,
                                           multi_bit_bool_t *success,
                                           multi_bit_bool_t clear);

#ifdef __cplusplus
}  // extern "C"
#endif  // __cplusplus

#endif  // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_SRAM_CTRL_H_
